home *** CD-ROM | disk | FTP | other *** search
- /* this file contains TSR.C, WINDOWS.C, and WINDOWS.H */
-
-
-
-
-
- /* Figure 6a -- TSR.C */
-
- /* TSR.C: Terminate and Stay Resident (TSR) program written entirely in Turbo C
- * ("look, ma, no assembly language!"). Bruce Eckel, Eisys Consulting,
- * 1009 N. 36th St., Seattle, WA 98103. 7/87.
- * The interrupt line on the parallel printer card (-ACK: pin 10 on the
- * DB-25 connector) is allowed through to IRQ7, and the 8259A is configured to
- * service the interrupt when -ACK is pulled to ground using a simple switch,
- * TTL or CMOS logic.
- * This was tested with an EGA monitor in color mode, so it probably works
- * with a color monitor or a monochrome monitor (for mono, change SCREEN_BASE
- * to 0xB000. Note I have gotten around using any DOS or BIOS calls by writing
- * direct screen driver routines -- this prevents any possible collision
- * with the program being interrupted.
- * I tried using the interrupt while running an EGA program (Dr Halo). The
- * results were...interesting. Someday maybe I'll figure that one out
- * (Sidekick worked, but it left garbage on the canvas).
- */
- /* #include <dos.h> */
- #define INT_NUMBER 15 /* interrupt number to install this function into.
- Note IRQ7 on the PC card bus corresponds to interrupt
- handler 15 in the interrupt vector table. */
- #define PROG_SIZE 0x1E10/* Run the Turbo C compiler with the options:linker:mapfile
- set to "segments." Look at the mapfile generated
- for this program. The "stop" address for the
- stack is the highest adress used -- set PROG_SIZE
- to this value for use with the "keep()" command */
- /* I tried using the "tiny" model instead of the "small" model, since it is
- supposed to be more size-efficient. The map showed the size to be LARGER,
- even though it didn't create a stack and the small model did. Seems odd. */
-
- #include "colors.h" /* color definitions */
- #include "windows.h" /* prototypes for window function definitions.
- These tell the compiler: (A) not to panic if a function is called for which
- it hasn't seen the definition, and (B) what the function's calling convention
- is, so the compiler can tell you if you're doing it right (helps find errors).*/
-
- #define BASE 0x378 /* Parallel port board base address, established for
- LPT1. Change this if you're using LPT2 or you
- changed the jumpers on the cheap card. */
-
- #define PIC_OCW1 0x21 /* 8259A Programmable Interrupt Controller
- Operation Control Word 1 (see issue 36, page 36 */
-
- /* macro to read value of ACK line */
- #define ACK (inportb(BASE + 1) & BIT6)
-
- /**************************************************************************/
- /* Macro (with parameters) to read values at any pin location. Returns */
- /* "1" if a logical one comes back from the masked pin, and "0" if a */
- /* logical zero comes back. Note inversions due to hardware logic are */
- /* not considered, so some pins may be seeing a TTL "1" and return a */
- /* zero (see circuit). */
- #define READ_BIT(port_address,bit) (inportb(port_address) & bit ? 1 : 0)
-
- /**************************************************************************/
- /* The interrupt handler. Notice the 'interrupt' compiler directive, */
- /* which tells the compiler to save and restore all the registers and */
- /* use interrupt code instead of normal subroutine code. */
- void interrupt int_handler()
- {
- #define LEFT_X 5 /* Window boundaries */
- #define RIGHT_X 75
- #define TOP_Y 5
- #define BOTTOM_Y 20
- /* Function prototype, to allow compiler to flag improper function calls: */
- void window_put_binary (int window_number, int value, unsigned char attribute);
-
- /* save the user's screen and put ours up instead */
- save_screen();
- define_window(0,LEFT_X,TOP_Y,RIGHT_X,BOTTOM_Y, YELLOW_CHAR | BROWN_BACK);
- draw_window(0);
- title_window(0,"Process Monitor Interrupt", RED_CHAR | GREEN_BACK);
-
- /* If you want to add sound here, see the Turbo C user's guide, page 275 */
-
- /* wait for the -ACK line to rise before returning. Meanwhile, read all
- the input lines (for example) with pullup resistors on them. */
- while (!ACK) { /* see how much neater the macro makes things? */
- window_gotoXY(0,LEFT_X+3,TOP_Y+2);
- window_puts (0,"pin 1 : ", BLACK_CHAR | BROWN_BACK);
- window_put_binary (0,READ_BIT(BASE+2,BIT0),
- BLUE_CHAR | BROWN_BACK);
- window_gotoXY(0,LEFT_X+35,TOP_Y+2);
- window_puts (0,"pin 14 : ", BLACK_CHAR | BROWN_BACK);
- window_put_binary (0,READ_BIT(BASE+2,BIT1),
- BLUE_CHAR | BROWN_BACK);
- window_gotoXY(0,LEFT_X+3,TOP_Y+7);
- window_puts (0,"pin 16 : ", BLACK_CHAR | BROWN_BACK);
- window_put_binary (0,READ_BIT(BASE+2,BIT2),
- BLUE_CHAR | BROWN_BACK);
- window_gotoXY(0,LEFT_X+35,TOP_Y+7);
- window_puts (0,"pin 17 : ", BLACK_CHAR | BROWN_BACK);
- window_put_binary (0,READ_BIT(BASE+2,BIT3),
- BLUE_CHAR | BROWN_BACK);
- }
-
- /* restore the user's previous screen */
- restore_screen();
-
- /* tell the 8259A Interrupt Controller we are finished executing IRQ7 */
- outportb(0x20,0x67); /* specific EOI for IRQ7 */
- }
-
- /**************************************************************************/
- /* main() for TSR. This installs the interrupt, sets up the hardware, */
- /* and exits leaving the program resident. Main is never used again. */
- main()
- {
- setvect(INT_NUMBER,int_handler); /* passes the ADDRESS of the beginning
- of the int_handler() function.
- setvect() is a Borland function. */
-
- /* change the bit on the parallel board to allow the -ACK interrupt to pass
- through to IRQ7 on the PC card bus. BIT4 allows the interrupt to pass;
- BIT2 allows pin 16 to be read. See circuit diagram. */
- outportb(BASE + 2, BIT4 | BIT2);
-
- /* zero top bit of OCW1 to allow IRQ7 to be serviced. Note we get the
- current OCW1, force the top bit to 0 and put it back out -- this retains
- the rest of the word (which affects other aspects of the machine) to
- prevent undesirable side effects. */
- outportb(PIC_OCW1, inportb(PIC_OCW1) & 0x7f);
-
- keep(0,PROG_SIZE); /* first parameter is exit status. See Ref. Manual. */
- }
-
- /**************************************************************************/
- /* Takes the bottom bit of an integer and prints it as an ascii string */
- /* either "0" or "1". For some reason, I had trouble passing string */
- /* pointers inside the TSR -- it would modify the save_buf[] array -- so */
- /* it seems I can only use literals. Be aware of this quirk -- I spent */
- /* awhile chasing it and couldn't find out what it was. */
- void
- window_put_binary (int window_number, int value, unsigned char attribute)
- {
- if (value & 1)
- window_puts (window_number,"1 ", attribute);
- else
- window_puts (window_number,"0 ", attribute);
- }
-
-
-
-
-
-
-
-
- /* Figure 6b -- WINDOWS.C */
-
- /* WINDOWS.C: custom screen functions to prevent DOS collisions inside the TSR.
- * Bruce Eckel, Eisys Consulting, 1009 N. 36th St. Seattle, WA 98103 7/87
- * "DOS calls!? We don't need no steenkin DOS calls!..." You can bet if
- * Borland had made DOS, it would have been re-entrant and relocatable, and we
- * wouldn't have this problem, or be limited to 640K on an AT.
- * Note I haven't put anything in to change the screen modes -- you are assumed
- * to already be in CGA. I also haven't turned the cursor off and on.
- */
-
- #undef TEST /* '#define' this to make a stand-alone test program */
- #include "colors.h" /* CGA color #defines */
- /* global place to save the screen so we can restore it when we're done: */
- unsigned char save_buf[SCREEN_CHARS];
-
- /* Now, a place for all the global attributes for each window: */
- struct window_def { /* coordinates start at upper left corner as 0,0 */
- int left_x; /* left-most extent of window */
- int top_y; /* upper limit of window */
- int right_x; /* right-most extent of window */
- int bottom_y; /* lower limit of window */
- unsigned char attributes; /* default char and background colors */
- int cursor_x; /* for functions which need cursors in the window */
- int cursor_y;
- } window[3]; /* To add more windows, increase the array size */
-
- #define WINDW window[window_number] /* saves typing and makes things clearer */
-
- /**************************************************************************/
- /* This function simply initializes a window[] structure, so all other */
- /* functions told to do something to that window can look up all the */
- /* necessary information about it. */
- void define_window(int window_number, int left_x, int top_y, int right_x,
- int bottom_y, unsigned char attribute)
- {
- WINDW.left_x = left_x; /* establish global window values */
- WINDW.top_y = top_y;
- WINDW.right_x = right_x;
- WINDW.bottom_y = bottom_y;
- WINDW.attributes = attribute;
- WINDW.cursor_x = left_x + 1; /* put cursor inside box */
- WINDW.cursor_y = top_y + 1;
- }
-
- /**************************************************************************/
- /* Puts a character and its attribute anywhere on the screen. */
- void putc_at_location(char ch, int x, int y, unsigned char attribute)
- {
- pokeb(SCREEN_BASE,((y * SCREEN_WIDTH) + x) * 2,ch);
- pokeb (SCREEN_BASE,(((y * SCREEN_WIDTH) + x) * 2) + 1, attribute);
- }
-
- /**************************************************************************/
- /* Clears a window (including the border), retaining it's attributes. */
- void clear_window(int window_number)
- {
- unsigned int x,y;
- for (y = WINDW.top_y; y <= WINDW.bottom_y ; y++){
- for (x = WINDW.left_x; x <= WINDW.right_x; x++){
- putc_at_location(' ',x,y,WINDW.attributes);
- }
- }
- }
-
- /**************************************************************************/
- /* Puts a string in a window, wrapping if it hits a border and refusing */
- /* to go past the lower right corner. For some reason, the string must */
- /* be a literal (i.e. '"a string"', rather than a pointer you pass) */
- /* embedded in the function call or bad things happen when the */
- /* interrupted screen is restored. */
- window_puts(int window_number, char *string, unsigned char attribute)
- {
- int cursor_offset;
- do {
- if (*string == 10) { /* check for newline */
- WINDW.cursor_x = WINDW.left_x + 1;
- WINDW.cursor_y += 1;
- if (WINDW.cursor_y > WINDW.bottom_y - 1)
- WINDW.cursor_y -= 1; /* just bump against the bottom if you run out */
- }
- else
- {
- putc_at_location(*string, WINDW.cursor_x, WINDW.cursor_y, attribute);
- /* Move cursor ahead, but keep it inside window */
- if (++WINDW.cursor_x > WINDW.right_x -1) {
- WINDW.cursor_x = WINDW.left_x + 1;
- if (++WINDW.cursor_y > WINDW.bottom_y -1)
- WINDW.cursor_y--;
- }}}
- while (*++string); /* stops at the string's null terminator */
- }
-
- /**************************************************************************/
- /* Saves the screen we just interrupted into a global array. */
- void
- save_screen()
- {
- int scr_offset;
- for(scr_offset = 0; scr_offset < SCREEN_CHARS; scr_offset++) {
- save_buf[scr_offset] = peekb(SCREEN_BASE,scr_offset);
- }
- }
-
- /**************************************************************************/
- /* Restores the interrupted screen from the global array. */
- void
- restore_screen()
- {
- int scr_offset;
- for(scr_offset = 0; scr_offset < SCREEN_CHARS; scr_offset++) {
- pokeb(SCREEN_BASE,scr_offset,save_buf[scr_offset]);
- }
- }
-
- /**************************************************************************/
- /* Puts a box of double bars (like Sidekick) around the window, using the */
- /* window's pre-defined character and background colors. */
- void make_box(int window_number)
- {
- int x,y;
-
- for (x=WINDW.left_x, y=WINDW.top_y; x++ < WINDW.right_x; ) /* top bar */
- putc_at_location(0xCD,x,y,WINDW.attributes);
- for (x=WINDW.left_x, y=WINDW.bottom_y; x++ < WINDW.right_x; ) /* bottom bar */
- putc_at_location(0xCD,x,y,WINDW.attributes);
- for (x=WINDW.left_x, y=WINDW.top_y; y++ < WINDW.bottom_y; ) /* left bar */
- putc_at_location(0xBA,x,y,WINDW.attributes);
- for (x=WINDW.right_x, y=WINDW.top_y; y++ < WINDW.bottom_y; ) /* right bar */
- putc_at_location(0xBA,x,y,WINDW.attributes);
-
- /* bottom left corner */
- putc_at_location(0xC8, WINDW.left_x, WINDW.bottom_y, WINDW.attributes);
- /* top left corner */
- putc_at_location(0xC9, WINDW.left_x, WINDW.top_y, WINDW.attributes);
- /* top right corner */
- putc_at_location(0xBB, WINDW.right_x, WINDW.top_y, WINDW.attributes);
- /* bottom right corner */
- putc_at_location(0xBC, WINDW.right_x, WINDW.bottom_y, WINDW.attributes);
- }
-
- /**************************************************************************/
- /* Puts window up if it isn't already; clears it if it is. */
- void draw_window(int window_number)
- {
- clear_window(window_number);
- make_box(window_number);
- }
-
- /**************************************************************************/
- /* Centers a title in the foreground and background colors of your choce.*/
- /* Title is placed in the top bar of the window. */
- void title_window(int window_number, char *title, unsigned char attribute)
- {
- char *title_ptr;
- int title_count, x;
- make_box(window_number); /* redraw box if new title is smaller than old one */
- for (title_ptr = title, title_count = 1; *++title_ptr; title_count++)
- ; /* count number of chars in string (stops when *title_ptr == '\0') */
- /* starting x value to center the title */
- x = (WINDW.right_x - WINDW.left_x - title_count)/2 + WINDW.left_x + 1;
- while (*title) /* stops when *title == '\0' */
- putc_at_location(*title++,x++,WINDW.top_y,attribute);
- }
-
- /**************************************************************************/
- /* Move the window cursor within the window, repecting the boundaries. */
- void window_gotoXY(int window_number, int X, int Y)
- {
- /* If X isn't outside of the window bounds, set cursor
- to X, else set it to just inside the window bounds */
- if (X > WINDW.left_x && X < WINDW.right_x )
- WINDW.cursor_x = X;
- else
- if (X <= WINDW.left_x)
- WINDW.cursor_x = WINDW.left_x +1;
- else
- WINDW.cursor_x = WINDW.right_x -1;
-
- /* same for y */
- if (Y > WINDW.top_y && Y < WINDW.bottom_y )
- WINDW.cursor_y = Y;
- else
- if (Y <= WINDW.top_y)
- WINDW.cursor_y = WINDW.top_y +1;
- else
- WINDW.cursor_y = WINDW.bottom_y -1;
- }
-
- #ifdef TEST
- main()
- {
- /* Here's where you put calls to window routines when performing stand-alone
- * tests. Of course, just because they work here doesn't mean they will work
- * in a TSR. You also need a '#define TEST' at the beginning of this file.
- */
- }
- #endif
-
-
-
-
-
-
-
-
- /* Figure 6c -- COLORS.H */
-
- /* COLORS.H: definitions for CGA screen characteristics and colors */
- #define SCREEN_BASE 0xb800 /* base address of color graphics card (and EGA
- in color graphics mode */
- #define SCREEN_HEIGHT 25
- #define SCREEN_WIDTH 80
- #define SCREEN_CHARS (SCREEN_WIDTH * SCREEN_HEIGHT * 2)
- /* number of chars and attributes in a screen */
-
- #define BIT0 0x01 /* bit masks */
- #define BIT1 0x02
- #define BIT2 0x04
- #define BIT3 0x08
- #define BIT4 0x10
- #define BIT5 0x20
- #define BIT6 0x40
- #define BIT7 0x80
-
- /* Make a complete attribute by ORing a CHARacter type with a BACKground type */
- #define BLUE_CHAR BIT0
- #define GREEN_CHAR BIT1
- #define RED_CHAR BIT2
- #define INTENSE BIT3
- #define BLUE_BACK BIT4
- #define GREEN_BACK BIT5
- #define RED_BACK BIT6
- #define BLINKING BIT7
-
- #define BLACK_CHAR 0
- #define CYAN_CHAR (GREEN_CHAR | BLUE_CHAR)
- #define MAGENTA_CHAR (RED_CHAR | BLUE_CHAR)
- #define BROWN_CHAR (RED_CHAR | GREEN_CHAR)
- #define WHITE_CHAR (RED_CHAR | GREEN_CHAR | BLUE_CHAR)
- #define GRAY_CHAR (INTENSE | BLACK_CHAR)
- #define LIGHT_BLUE_CHAR (INTENSE | BLUE_CHAR)
- #define LIGHT_GREEN_CHAR (INTENSE | GREEN_CHAR)
- #define LIGHT_CYAN_CHAR (INTENSE | CYAN_CHAR)
- #define LIGHT_RED_CHAR (INTENSE | RED_CHAR)
- #define LIGHT_MAGENTA_CHAR (INTENSE | MAGENTA_CHAR)
- #define YELLOW_CHAR (INTENSE | BROWN_CHAR)
- #define BRIGHT_WHITE_CHAR ( INTENSE | WHITE_CHAR)
-
- #define BLACK_BACK 0
- #define CYAN_BACK (GREEN_BACK | BLUE_BACK)
- #define MAGENTA_BACK (RED_BACK | BLUE_BACK)
- #define BROWN_BACK (RED_BACK | GREEN_BACK)
- #define WHITE_BACK (RED_BACK | GREEN_BACK | BLUE_BACK)
- #define GRAY_BACK (INTENSE | BLACK_BACK)
- #define LIGHT_BLUE_BACK (INTENSE | BLUE_BACK)
- #define LIGHT_GREEN_BACK (INTENSE | GREEN_BACK)
- #define LIGHT_CYAN_BACK (INTENSE | CYAN_BACK)
- #define LIGHT_RED_BACK (INTENSE | RED_CHAR)
- #define LIGHT_MAGENTA_BACK (INTENSE | MAGENTA_CHAR)
- #define YELLOW_BACK (INTENSE | BROWN_BACK)
- #define BRIGHT_WHITE_BACK ( INTENSE | WHITE_BACK)
-
-
-
-
- /* Figure 6d -- WINDOWS.H */
-
- /* WINDOWS.H: #include these function prototypes at the beginning of any file
- * where you use windows functions. Turbo C will then catch errors if you
- * call the functions improperly. (to "make" properly, you also need to
- * mention windows.c in your "project" file).
- */
-
- extern void define_window(int window_number, int left_x, int top_y, int right_x,
- int bottom_y, unsigned char attribute);
-
- extern void putc_at_location(char ch, int x, int y, unsigned char attribute);
-
- extern void clear_window(int window_number);
-
- window_puts(int window_number, char *string, unsigned char attribute);
-
- extern void save_screen();
-
- extern void restore_screen();
-
- extern void make_box(int window_number);
-
- extern void draw_window(int window_number);
-
- extern void title_window(int window_number, char *title,
- unsigned char attribute);
-
- extern void window_gotoXY(int window_number, int X, int Y);
-